import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import copy


"""
    时间：2019/10/22
    作者：徐飞
    内容：20期第二次作业
"""
"""
1.以Lena为原始图像，通过OpenCV实现平均滤波，高斯滤波及中值滤波，比较滤波结果。
"""
file = r"lena.png"
img1 = cv.imread(file)
img1 = cv.resize(img1, (350, 350))
blur = cv.blur(img1, (3, 3))
Gauss = cv.GaussianBlur(img1, (3, 3), 1)
median = cv.medianBlur(img1, 5)
element = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))
morphology = cv.morphologyEx(img1, cv.MORPH_OPEN, element)

cv.imshow("original image", img1)   # 原始图像
cv.imshow("blur image", blur)  # 平均滤波
cv.imshow("Gauss image", img1)   # 高斯滤波
cv.imshow("median image", median)   # 中值滤波
cv.imshow("morphology image", morphology)   # 几何学滤波

cv.waitKey(0)
cv.destroyAllWindows()
"""
对比结果：通过对平均滤波、中值滤波、高斯滤波、形态学滤波各滤波的对比结果可以看出。
         中值滤波在假发部位出现模糊比较严重，形态学滤波在假发部位出现马赛克现象，
         而平均滤波和高斯滤波平滑后的结果相对比较清楚。
"""

"""
2. 以Lena为原始图像，通过OpenCV使用Sobel及Canny算子检测，比较边缘检测结果。
"""
# file = r"lena.png"
# img2 = cv.imread(file)
# gray = cv.cvtColor(img2, cv.COLOR_BGR2GRAY) # 转化成灰色图像
# x_label = cv.Sobel(gray, cv.CV_16S, 1, 0)
# y_label = cv.Sobel(gray, cv.CV_16S, 0, 1)
# x = cv.convertScaleAbs(x_label)
# y = cv.convertScaleAbs(y_label)
# sober = cv.addWeighted(x, 0.5, y, 0.5, 0)
# canny = cv.Canny(x_label, y_label, 50, 100)
# cv.imshow("gray image", gray)
# cv.imshow("Sober image", sober)
# cv.imshow("canny image", canny)
# cv.waitKey(0)
# cv.destroyAllWindows()

"""
对比结果：Sober算子能大致勾勒出人物外形轮廓，但出现了许多噪声影响。
         Canny算子勾勒出的曲线更加清晰，基本没什么噪声影响。
"""

"""
3.在OpenCV安装目录下找到课程对应演示图片(安装目录\sources\samples\data)，
  首先计算灰度直方图，进一步使用大津算法进行分割，并比较分析分割结果。
"""
# file1 = r"pic2.png"
# file2 = r"pic6.png"
# img1 = cv.imread(file1)
# img2 = cv.imread(file2)
# gray1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)
# gray2 = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)
# # 灰度直方图
# hist1 = cv.calcHist([gray1], [0], None, [256], [0, 256])    # 计算灰度直方图（固定方式）
# hist2 = cv.calcHist([gray2], [0], None, [256], [0, 256])
# # 图一灰度直方图
# plt.plot(hist1)
# plt.title('hist1')
# plt.xlim([0, 256])
# plt.show()
# # 图二灰度直方图
# plt.plot(hist2)
# plt.title('hist2')
# plt.xlim([0, 256])
# plt.show()
# # 图一运用大津算法
# median = cv.medianBlur(gray1, 5)
# _, OTS_1 = cv.threshold(median, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# cv.imshow("OTSU1 image", OTS_1)
# # 图二运用大津算法
# blur = cv.blur(gray2, (3, 3))
# _, OTS_2 = cv.threshold(blur, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# cv.imshow("OTSU2 image", OTS_2)
#
# cv.waitKey(0)
# cv.destroyAllWindows()


"""
4.使用米粒图像，分割得到各米粒，首先计算各区域(米粒)的面积、长度等信息，
  进一步计算面积、长度的均值及方差，分析落在3sigma范围内米粒的数量。
"""
# file = r"rice.png"
# img = cv.imread(file, 1)
# img = cv.resize(img, (400, 400))
# gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#
# # 局部大津算法
# dst = cv.adaptiveThreshold(gray, 256, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 101, 1)
# element = cv.getStructuringElement(cv.MORPH_CROSS, (3, 3))  # 形态学运算结构元素
# bw = cv.morphologyEx(dst, cv.MORPH_OPEN, element)  # 形态学滤波
#
# copy = copy.deepcopy(bw)    # 复制一份
# bins, cnts, hier = cv.findContours(copy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)    # 检测米粒轮廓
# # 信息汇总
# number = 0
# area_array = np.array([])   # 面积数组
# length_array = np.array([])    # 长度数组
# for i in range(len(cnts), 0, -1):
#     cnt = cnts[i - 1]
#     area = cv.contourArea(cnt)    # 计算面积
#     if area < 10:
#         continue
#     area_array = np.append(area_array, area)
#     number += 1
#     min_area_rec = cv.minAreaRect(cnt)    # 精确米粒边界
#     x, y, w, h = cv.boxPoints(min_area_rec)    # 得到米粒的4个坐标
#     # 计算米粒长度
#     line1 = ((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2) ** 0.5
#     line2 = ((x[0] - h[0]) ** 2 + (x[1] - h[1]) ** 2) ** 0.5
#     if line1 > line2:
#         line = line1
#     else:
#         line = line2
#     length_array = np.append(length_array, line)
#     print("米粒：{}，面积：{}，长度：{}".format(i, area, round(line, 2)))
#     cv.line(img, tuple(x), tuple(y), (255, 0, 0), 1)
#     cv.line(img, tuple(y), tuple(w), (255, 0, 0), 1)
#     cv.line(img, tuple(w), tuple(h), (255, 0, 0), 1)
#     cv.line(img, tuple(h), tuple(x), (255, 0, 0), 1)
#     cv.putText(img, str(cnt), (x[0], x[1]), cv.FONT_HERSHEY_PLAIN, 0.5, (0, 256, 0))    # 标记字体信息
# print("*"*40)
# # 面积参数统计
# area_all = round(area_array.sum(), 2)   # 总面积
# area_aver = round(area_all / number, 2)     # 平均面积
# area_std = round(area_array.std(), 2)
# print("米粒总数：{}，总面积：{}，平均面积：{}，面积标准差：{}".format(len(area_array), area_all, area_aver, area_std))
# area1 = round(area_aver - area_std * 1.5, 2)
# area2 = round(area_aver + area_std * 1.5, 2)
# print("落在3sigma内米粒面积范围：{}--{}".format(area1, area2))
# number1 = 0
# for i in area_array:
#     if area1 < i < area2:
#         number1 += 1
# print("落在3sigma内米粒数量：{}".format(number1))
#
# print("*"*40)
# # 长度参数统计
# length_all = round(length_array.sum(), 2)   # 总面积
# length_aver = round(length_all / number, 2)     # 平均面积
# length_std = round(length_array.std(), 2)
# print("米粒总数：{}，总面积：{}，平均面积：{}，面积标准差：{}".format(len(length_array), length_all, length_aver, length_std))
# length1 = round(length_aver - length_std * 1.5, 2)
# length2 = round(length_aver + length_std * 1.5, 2)
# print("落在3sigma内米粒面积范围：{}--{}".format(length1, length2))
# number2 = 0
# for i in length_array:
#     if length1 < i < length2:
#         number2 += 1
# print("落在3sigma内米粒数量：{}".format(number2))
#
# cv.imshow("gray image", gray)
# cv.imshow("oust image", dst)
# cv.imshow("split image", img)
#
# cv.waitKey(0)
# cv.destroyAllWindows()
